/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    rng.c
  * @brief   This file provides code for the configuration
  *          of the RNG instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include "rng.h"
#include "crypt_errno.h"
#include "bsl_sal.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

RNG_HandleTypeDef hrng;

/* RNG init function */
void MX_RNG_Init(void)
{

    /* USER CODE BEGIN RNG_Init 0 */

    /* USER CODE END RNG_Init 0 */

    /* USER CODE BEGIN RNG_Init 1 */

    /* USER CODE END RNG_Init 1 */
    hrng.Instance = RNG;
    if (HAL_RNG_Init(&hrng) != HAL_OK)
    {
        Error_Handler();
    }
    /* USER CODE BEGIN RNG_Init 2 */

    /* USER CODE END RNG_Init 2 */

}

void HAL_RNG_MspInit(RNG_HandleTypeDef* rngHandle)
{

    if(rngHandle->Instance==RNG)
    {
        /* USER CODE BEGIN RNG_MspInit 0 */

        /* USER CODE END RNG_MspInit 0 */
        /* RNG clock enable */
        __HAL_RCC_RNG_CLK_ENABLE();
        /* USER CODE BEGIN RNG_MspInit 1 */

        /* USER CODE END RNG_MspInit 1 */
    }
}

void HAL_RNG_MspDeInit(RNG_HandleTypeDef* rngHandle)
{

    if(rngHandle->Instance==RNG)
    {
        /* USER CODE BEGIN RNG_MspDeInit 0 */

        /* USER CODE END RNG_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_RNG_CLK_DISABLE();
        /* USER CODE BEGIN RNG_MspDeInit 1 */

        /* USER CODE END RNG_MspDeInit 1 */
    }
}

/* USER CODE BEGIN 1 */
int32_t stm32_getEntropy(void *ctx, CRYPT_Data *entropy, uint32_t strength, CRYPT_Range *lenRange)
{
    (void)ctx;
    (void)strength;
    if (!entropy || !lenRange) return CRYPT_NULL_INPUT;

    // 取长度（取 min/max 推荐值，可以自定义）
    uint32_t req_len = lenRange->min;
    uint8_t *buffer = malloc(req_len);
    if (!buffer) return CRYPT_MEM_ALLOC_FAIL;
    entropy->len = req_len;

    uint32_t *buf32 = (uint32_t *)buffer;
    const uint32_t words = req_len / 4;
    const uint32_t remain = req_len % 4;

    for (uint32_t i = 0; i < words; i++) {
        if (HAL_RNG_GenerateRandomNumber(&hrng, &buf32[i]) != HAL_OK) {
            free(buffer);
            return CRYPT_DRBG_FAIL_GET_ENTROPY;
        }
    }
    if (remain > 0) {
        uint32_t last_word;
        if (HAL_RNG_GenerateRandomNumber(&hrng, &last_word) != HAL_OK) {
            free(buffer);
            return CRYPT_DRBG_FAIL_GET_ENTROPY;
        }
        memcpy(buffer + (words * 4), &last_word, remain);
    }

    /* 返回结果 */
    entropy->data = buffer;
    entropy->len = req_len;
    return CRYPT_SUCCESS;
}

void stm32_cleanEntropy(void *ctx, CRYPT_Data *entropy)
{
    (void)ctx;
    BSL_SAL_CleanseData(entropy->data, entropy->len);
    BSL_SAL_FREE(entropy->data);
}

int32_t stm32_getNonce(void *ctx, CRYPT_Data *nonce, uint32_t strength, CRYPT_Range *lenRange)
{
    return stm32_getEntropy(ctx, nonce, strength, lenRange);
}

void stm32_cleanNonce(void *ctx, CRYPT_Data *nonce)
{
    stm32_cleanEntropy(ctx,nonce);
}

int32_t myRand(uint8_t *buf, uint32_t len)
{
    uint32_t i = 0;
    while (i < len) {
        uint32_t rnd32;
        if (HAL_RNG_GenerateRandomNumber(&hrng, &rnd32) != HAL_OK) {
            return -1;
        }
        size_t cplen = (len - i) > 4 ? 4 : (len - i);
        memcpy(buf + i, &rnd32, cplen);
        i += cplen;
    }
    return CRYPT_SUCCESS;
}
/* USER CODE END 1 */
